home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Skunkware 5
/
Skunkware 5.iso
/
src
/
X11
/
xmbase-grok-1.2
/
querywin.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-06-25
|
17KB
|
584 lines
/*
* Create and destroy default query menu and all widgets in them. All widgets
* are labels or pushbuttons; they are faster than text buttons. Whenever
* the user presses a button with text in it, it is overlaid with a Text
* button. The query menu is started from the form editor, default queries
* are expressions attached to a form. They appear in the Query pulldown.
*
* add_dquery(form) apend a query entry to the form's list
* destroy_query_window() remove query popup
* create_query_window() create query popup
*/
#include "config.h"
#include <X11/Xos.h>
#include <stdlib.h>
#include <pwd.h>
#include <Xm/Xm.h>
#include <Xm/Form.h>
#include <Xm/LabelP.h>
#include <Xm/LabelG.h>
#include <Xm/PushBP.h>
#include <Xm/PushBG.h>
#include <Xm/ToggleB.h>
#include <Xm/ScrolledW.h>
#include <Xm/Text.h>
#include <Xm/Protocols.h>
#include "grok.h"
#include "form.h"
#include "proto.h"
#define NCOLUMNS 4 /* # of widget columns in query list */
static void create_query_rows(void);
static void edit_query_button(BOOL, int, int);
static void got_query_text(int, int, char *);
static void draw_row(int);
static void delete_callback(Widget, int, XmToggleButtonCallbackStruct *);
static void dupl_callback (Widget, int, XmToggleButtonCallbackStruct *);
static void done_callback (Widget, int, XmToggleButtonCallbackStruct *);
static void list_callback (Widget, int, XmToggleButtonCallbackStruct *);
static void got_text (Widget, int, XmToggleButtonCallbackStruct *);
extern Display *display; /* everybody uses the same server */
extern GC gc; /* everybody uses this context */
extern Pixel color[NCOLS]; /* colors: COL_* */
extern Pixmap pixmap[NPICS]; /* common symbols */
extern struct config config; /* global configuration data */
static FORM *form; /* form whose queries are edited */
static BOOL have_shell; /* message popup exists if TRUE */
static Widget shell; /* popup menu shell */
static Widget delete, dupl; /* buttons, for desensitizing */
static Widget info; /* info line for error messages */
static Widget textwidget; /* if editing, text widget; else 0 */
static int have_nrows; /* # of table widget rows allocated */
static int xedit, yedit; /* if editing, column/row */
static int ycurr; /* current row, 0=none, 1=1st query..*/
static Widget qlist; /* query list RowColumn widget */
static Widget (*qtable)[NCOLUMNS]; /* all widgets in query list table */
/* [0][*] is title row */
/*
* add a query entry. This is used when a new entry is started by pressing on
* an empty row, or when duplicating an entry, or when a form file is read.
*/
DQUERY *add_dquery(
FORM *fp) /* form to add blank entry to */
{
int n = ++fp->nqueries * sizeof(DQUERY);
if (!(fp->query = (DQUERY *)(fp->query ? realloc((char *)fp->query, n)
: malloc(n))))
fatal("no memory for query");
mybzero((void *)&fp->query[fp->nqueries-1], sizeof(DQUERY));
return(&fp->query[fp->nqueries-1]);
}
/*
* destroy the popup. Remove it from the screen, and destroy its widgets.
*/
void destroy_query_window(void)
{
if (have_shell) {
XtPopdown(shell);
XtDestroyWidget(shell);
have_shell = FALSE;
}
}
/*
* create a query popup as a separate application shell.
*/
void create_query_window(
FORM *newform) /*form whose queries are chgd*/
{
Widget wform, scroll, w;
Arg args[15];
int n;
Atom closewindow;
destroy_query_window();
if (have_shell)
return;
form = newform;
n = 0;
XtSetArg(args[n], XmNdeleteResponse, XmUNMAP); n++;
XtSetArg(args[n], XmNiconic, False); n++;
shell = XtAppCreateShell("Default Queries", "Grok",
applicationShellWidgetClass, display, args, n);
set_icon(shell, 1);
wform = XtCreateWidget("queryform", xmFormWidgetClass,
shell, NULL, 0);
XtAddCallback(wform, XmNhelpCallback,
(XtCallbackProc)help_callback, (XtPointer)"queries");
/*-- buttons --*/
n = 0;
XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNbottomOffset, 8); n++;
XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNleftOffset, 8); n++;
XtSetArg(args[n], XmNwidth, 80); n++;
XtSetArg(args[n], XmNsensitive, False); n++;
delete = w = XtCreateManagedWidget("Delete", xmPushButtonWidgetClass,
wform, args, n);
XtAddCallback(w, XmNactivateCallback,
(XtCallbackProc)delete_callback, (XtPointer)0);
XtAddCallback(w, XmNhelpCallback,
(XtCallbackProc)help_callback, (XtPointer)"dq_delete");
n = 0;
XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNbottomOffset, 8); n++;
XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
XtSetArg(args[n], XmNleftWidget, w); n++;
XtSetArg(args[n], XmNleftOffset, 8); n++;
XtSetArg(args[n], XmNwidth, 80); n++;
XtSetArg(args[n], XmNsensitive, False); n++;
dupl = w = XtCreateManagedWidget("Duplicate", xmPushButtonWidgetClass,
wform, args, n);
XtAddCallback(w, XmNactivateCallback,
(XtCallbackProc)dupl_callback, (XtPointer)0);
XtAddCallback(w, XmNhelpCallback,
(XtCallbackProc)help_callback, (XtPointer)"dq_dupl");
n = 0;
XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNbottomOffset, 8); n++;
XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNrightOffset, 8); n++;
XtSetArg(args[n], XmNwidth, 80); n++;
w = XtCreateManagedWidget("Done", xmPushButtonWidgetClass,
wform, args, n);
XtAddCallback(w, XmNactivateCallback,
(XtCallbackProc)done_callback, (XtPointer)0);
XtAddCallback(w, XmNhelpCallback,
(XtCallbackProc)help_callback, (XtPointer)"dq_done");
n = 0;
XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNbottomOffset, 8); n++;
XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++;
XtSetArg(args[n], XmNrightWidget, w); n++;
XtSetArg(args[n], XmNrightOffset, 8); n++;
XtSetArg(args[n], XmNwidth, 80); n++;
w = XtCreateManagedWidget("Help", xmPushButtonWidgetClass,
wform, args, n);
XtAddCallback(w, XmNactivateCallback,
(XtCallbackProc)help_callback, (XtPointer)"queries");
XtAddCallback(w, XmNhelpCallback,
(XtCallbackProc)help_callback, (XtPointer)"queries");
/*-- infotext -- */
n = 0;
XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNleftOffset, 8); n++;
XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNrightOffset, 8); n++;
XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNtopOffset, 8); n++;
XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
info = XtCreateManagedWidget(" ", xmLabelGadgetClass,
wform, args, n);
/*-- scroll --*/
n = 0;
XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
XtSetArg(args[n], XmNtopWidget, info); n++;
XtSetArg(args[n], XmNtopOffset, 8); n++;
XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
XtSetArg(args[n], XmNbottomWidget, w); n++;
XtSetArg(args[n], XmNbottomOffset, 16); n++;
XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNleftOffset, 8); n++;
XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNrightOffset, 8); n++;
XtSetArg(args[n], XmNwidth, 580); n++;
XtSetArg(args[n], XmNheight, 300); n++;
XtSetArg(args[n], XmNscrollingPolicy, XmAUTOMATIC); n++;
scroll = XtCreateWidget("qscroll", xmScrolledWindowWidgetClass,
wform, args, n);
XtAddCallback(scroll, XmNhelpCallback,
(XtCallbackProc)help_callback, (XtPointer)"queries");
n = 0;
qlist = XtCreateManagedWidget("qlist", xmBulletinBoardWidgetClass,
scroll, args, n);
create_query_rows(); /* have_shell must be FALSE here */
print_query_info();
XtManageChild(scroll);
XtManageChild(wform);
XtPopup(shell, XtGrabNone);
closewindow = XmInternAtom(display, "WM_DELETE_WINDOW", False);
XmAddWMProtocolCallback(shell, closewindow,
(XtCallbackProc)done_callback, (XtPointer)shell);
have_shell = TRUE;
}
/*
* makes sure there are enough widget rows for query entries. Also makes
* sure that there aren't too many, for speed reasons. Allocate one extra
* widget row for the title at the top. All the text buttons are
* label widgets. For performance reasons, they are overlaid by a text
* widget when pressed.
* No text is printed into the buttons, this is done later by draw_row().
*/
static short cell_x [NCOLUMNS] = { 4, 44, 84, 284 };
static short cell_xs [NCOLUMNS] = { 30, 30, 200, 1000 };
static char *cell_name [NCOLUMNS] = { "on", "def", "Name", "Query Expression"};
static void create_query_rows(void)
{
int nrows = form->nqueries+3 - form->nqueries%3;
int x, y;
Arg args[15];
int n;
char *name;
WidgetClass class;
if (!have_shell) /* check # of rows: */
have_nrows = 0;
if (nrows <= have_nrows)
return;
n = (nrows+1) * NCOLUMNS * sizeof(Widget *);
if (qtable && !(qtable = (Widget (*)[])realloc(qtable, n)) ||
!qtable && !(qtable = (Widget (*)[])malloc(n)))
fatal("no memory");
for (x=0; x < NCOLUMNS; x++) {
for (y=have_nrows; y <= nrows; y++) {
XtUnmanageChild(qlist);
name = cell_name[x];
class = xmPushButtonWidgetClass;
n = 0;
if (y) {
if (x < 2) {
class = xmToggleButtonWidgetClass;
XtSetArg(args[n], XmNselectColor,
color[COL_TOGGLE]); n++;
}
if (x == 1) {
XtSetArg(args[n], XmNindicatorType,
XmONE_OF_MANY); n++;
}
name = " ";
} else
class = xmLabelWidgetClass;
XtSetArg(args[n], XmNx, cell_x[x]); n++;
XtSetArg(args[n], XmNy, 10 + 30*y); n++;
XtSetArg(args[n], XmNwidth, cell_xs[x]); n++;
XtSetArg(args[n], XmNheight, 30); n++;
XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
XtSetArg(args[n], XmNrecomputeSize, False); n++;
XtSetArg(args[n], XmNtraversalOn, True); n++;
XtSetArg(args[n], XmNhighlightThickness,0); n++;
XtSetArg(args[n], XmNshadowThickness, x > 1 && y); n++;
qtable[y][x] = XtCreateManagedWidget(name, class,
qlist, args, n);
if (y)
XtAddCallback(qtable[y][x],
x > 1 ? XmNactivateCallback
: XmNvalueChangedCallback,
(XtCallbackProc)list_callback,
(XtPointer)((long)(x + y * NCOLUMNS)));
XtAddCallback(qtable[y][x], XmNhelpCallback,
(XtCallbackProc)help_callback,
(XtPointer)"queries");
}
}
for (y=have_nrows; y <= nrows; y++)
draw_row(y);
have_nrows = nrows;
XtManageChild(qlist);
}
/*-------------------------------------------------- editing ----------------*/
/*
* turn a text label into a Text button, to allow user input. This is done
* by simply installing a text widget on top of the label widget. The proper
* query name or expression is put into the text widget. The previously edited
* button is un-edited.
*/
static void edit_query_button(
BOOL doedit, /* TRUE=edit, FALSE=unedit */
int x, /* column, 0..NCOLUMNS-1* */
int y) /* row, y=0: title */
{
Arg args[15];
int n;
char *text;
if (textwidget) {
char *string = XmTextGetString(textwidget);
got_query_text(xedit, yedit, string);
XtFree(string);
XtDestroyWidget(textwidget);
draw_row(yedit);
create_query_rows();
}
textwidget = 0;
if (!doedit)
return;
if (y > form->nqueries+1)
y = form->nqueries+1;
n = 0;
XtSetArg(args[n], XmNx, cell_x[x]); n++;
XtSetArg(args[n], XmNy, 10 + 30*y); n++;
XtSetArg(args[n], XmNwidth, cell_xs[x]); n++;
XtSetArg(args[n], XmNheight, 30); n++;
XtSetArg(args[n], XmNrecomputeSize, False); n++;
XtSetArg(args[n], XmNpendingDelete, True); n++;
XtSetArg(args[n], XmNhighlightThickness,0); n++;
XtSetArg(args[n], XmNshadowThickness, 1); n++;
XtSetArg(args[n], XmNbackground, color[COL_TEXTBACK]); n++;
textwidget = XtCreateManagedWidget("text", xmTextWidgetClass,
qlist, args, n);
XtAddCallback(textwidget, XmNactivateCallback,
(XtCallbackProc)got_text, (XtPointer)0);
XtAddCallback(textwidget, XmNhelpCallback,
(XtCallbackProc)help_callback, (XtPointer)"queries");
XmProcessTraversal(textwidget, XmTRAVERSE_CURRENT);
text = y > form->nqueries ? "" : x == 2 ? form->query[y-1].name
: form->query[y-1].query;
print_text_button_s(textwidget, text);
xedit = x;
yedit = y;
}
static void got_query_text(
int x, /* column, 0..NCOLUMNS-1* */
int y, /* row, y=0: title */
char *string) /* text entered by user */
{
register DQUERY *dq; /* query entry */
if (!y--)
return;
if (y >= form->nqueries) {
(void)add_dquery(form);
y = form->nqueries - 1;
}
dq = &form->query[y];
if (x == 2) { /* name */
if (dq->name)
free(dq->name);
dq->name = mystrdup(string);
} else { /* query expr */
if (dq->query)
free(dq->query);
dq->query = mystrdup(string);
}
}
/*
* draw all buttons of row y. y must be > 0 because 0 is the title row.
* If y is > form->nqueries, the row is blanked.
*/
static void draw_row(
int y)
{
Arg arg;
register DQUERY *dq = &form->query[y-1];
if (y < 1)
return;
if (y <= form->nqueries) { /* valid row */
XtSetArg(arg, XmNset, !dq->suspended);
XtSetValues (qtable[y][0], &arg, 1);
XtSetArg(arg, XmNset, form->autoquery == y-1);
XtSetValues (qtable[y][1], &arg, 1);
print_button(qtable[y][2], dq->name ? dq->name : " ");
print_button(qtable[y][3], dq->query ? dq->query : " ");
} else { /* blank row */
XtSetArg(arg, XmNset, 0);
XtSetValues (qtable[y][0], &arg, 1);
XtSetValues (qtable[y][1], &arg, 1);
print_button(qtable[y][2], " ");
print_button(qtable[y][3], " ");
}
}
/*
* print interesting info into the message line. This is done only once, when
* the menu is created.
*/
void print_query_info(void)
{
char msg[4096]; /* message buffer */
int i; /* index to next free char in msg */
char comma = ' '; /* delimiter between message items */
int item; /* item (field) counter */
ITEM *ip; /* current item (field) */
strcpy(msg, "Fields:");
i = strlen(msg);
for (item=0; item < form->nitems; item++) {
ip = form->items[item];
switch(ip->type) {
case IT_INPUT:
case IT_TIME:
case IT_NOTE:
sprintf(msg+i, "%c %s", comma, ip->name);
break;
case IT_FLAG:
case IT_CHOICE:
sprintf(msg+i, "%c %s=%s", comma, ip->name,
ip->flagcode);
break;
default:
continue;
}
i += strlen(msg+i);
comma = ',';
if (i > sizeof(msg)-100)
break;
}
if (comma == ' ')
strcpy(msg+i, "none");
print_button(info, msg);
}
/*-------------------------------------------------- callbacks --------------*/
/*
* Delete, Duplicate, and Done buttons.
* All of these routines are direct X callbacks.
*/
/*ARGSUSED*/
static void delete_callback(
Widget widget,
int item,
XmToggleButtonCallbackStruct *data)
{
int n;
Arg args;
if (ycurr && ycurr <= form->nqueries) {
edit_query_button(FALSE, 0, 0);
for (n=ycurr-1; n < form->nqueries; n++)
form->query[n] = form->query[n+1];
form->nqueries--;
for (n=ycurr; n <= have_nrows; n++)
draw_row(n);
}
if (!ycurr) {
XtSetArg(args, XmNsensitive, 0);
XtSetValues(delete, &args, 1);
XtSetValues(dupl, &args, 1);
}
}
/*ARGSUSED*/
static void dupl_callback(
Widget widget,
int item,
XmToggleButtonCallbackStruct *data)
{
int n;
if (form->nqueries) {
edit_query_button(FALSE, 0, 0);
(void)add_dquery(form);
create_query_rows();
for (n=form->nqueries-1; n > ycurr-1; n--)
form->query[n] = form->query[n-1];
form->query[n].name = mystrdup(form->query[n].name);
form->query[n].query = mystrdup(form->query[n].query);
for (n=ycurr; n <= form->nqueries; n++)
draw_row(n);
}
}
/*ARGSUSED*/
static void done_callback(
Widget widget,
int item,
XmToggleButtonCallbackStruct *data)
{
edit_query_button(FALSE, 0, 0);
destroy_query_window();
remake_query_pulldown();
}
/*
* one of the buttons in the list was pressed
*/
/*ARGSUSED*/
static void list_callback(
Widget widget,
int item,
XmToggleButtonCallbackStruct *data)
{
int x = item % NCOLUMNS;
int y = item / NCOLUMNS;
Arg arg;
int i;
if (y > form->nqueries) { /* new entry */
x = 2;
edit_query_button(TRUE, x, ycurr = form->nqueries+1);
} else { /* old entry */
ycurr = y;
switch(x) {
case 0:
form->query[y-1].suspended = !data->set;
break;
case 1:
i = form->autoquery;
form->autoquery = y-1;
draw_row(i+1);
draw_row(y);
break;
default:
edit_query_button(TRUE, x, y);
}
}
XtSetArg(arg, XmNsensitive, ycurr > 0);
XtSetValues(delete, &arg, 1);
XtSetValues(dupl, &arg, 1);
}
/*
* the user pressed Return in a text entry button
*/
/*ARGSUSED*/
static void got_text(
Widget widget,
int item,
XmToggleButtonCallbackStruct *data)
{
edit_query_button(FALSE, 0, 0);
}